﻿/*  
	------------------------------------------------------------------------
	 NQ Core Library
	
	 Homepage: http://www.awzhome.de/
	------------------------------------------------------------------------
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of NQ Core Library.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AWZhome.NQ.Core.Fluent
{
	/// <summary>
	/// Provides a fluent interface to the NQ Service Manager.
	/// </summary>
	public static class ServiceCore
	{
		private static LogWrapper<object> _logWrapper = new LogWrapper<object>(null);

		/// <summary>
		/// Retrieves the value of a command line parameter.
		/// </summary>
		/// <param name="paramname">Parameter name, without prefixes like <c>/</c> or <c>-</c>.</param>
		/// <returns>A string array with parameter data (a file name, for example).</returns>
		/// <remarks>
		/// The standard implementation <see cref="AWZhome.NQ.Core.NQServiceManager">NQServiceManager</see> assumes the command
		/// line parameters to be of following format:
		/// <code>app.exe -p1 data1 data2 -p2 data3 -p3 -p4</code>
		/// where <c>-p1</c> to <c>-p4</c> are the parameter names and <c>data1</c> to <c>data4</c> the parameter data.
		/// </remarks>
		public static string[] Param(string paramname)
		{
			return NQServiceManager.Instance.GetCmdLineParam(paramname);
		}

		/// <summary>
		/// Checks if a command-line parameter is set.
		/// </summary>
		/// <param name="paramname">Parameter name, without prefixes like <c>/</c> or <c>-</c>.</param>
		/// <returns><c>True</c>, if command-line parameter is set, <c>false</c> otherwise.</returns>
		public static bool IsParam(string paramname)
		{
			return NQServiceManager.Instance.IsCmdLineParamSet(paramname);
		}

		/// <summary>
		/// Returns a log wrapper to access the log functionality
		/// of NQ Service Manager.
		/// </summary>
		public static LogWrapper<object> Log
		{
			get
			{
				return _logWrapper;
			}
		}

		/// <summary>
		/// Returns the instance of a single-instance service.
		/// </summary>
		/// <typeparam name="T">Type of the retrieved service.</typeparam>
		/// <returns>Service instance wrapper.</returns>
		public static SingleServiceInstanceWrapper<T> Get<T>()
		{
			return new SingleServiceInstanceWrapper<T>();
		}

		/// <summary>
		/// Creates the instance of a multi-instance service.
		/// </summary>
		/// <typeparam name="T">Type of the retrieved service.</typeparam>
		/// <returns>Service instance wrapper.</returns>
		public static LazyCreatedServiceWrapper<T> Create<T>()
		{
			return new LazyCreatedServiceWrapper<T>();
		}

		/// <summary>
		/// Retrieves instances of all services from an AttachList without casting
		/// the retrieved instances to any special type.
		/// </summary>
		/// <param name="attachListName">AttachList name.</param>
		/// <returns>Service instance wrapper.</returns>
		public static LazyCreatedDepServiceListWrapper<object> RetrieveAttached(string attachListName)
		{
			return RetrieveAttached<object>(attachListName);
		}

		/// <summary>
		/// Retrieves instances of all services from an AttachList.
		/// </summary>
		/// <typeparam name="T">Type of the services in the AttachList.</typeparam>
		/// <param name="attachListName">AttachList name.</param>
		/// <returns>Service instance wrapper.</returns>
		public static LazyCreatedDepServiceListWrapper<T> RetrieveAttached<T>(string attachListName)
		{
			return new LazyCreatedDepServiceListWrapper<T>(attachListName);
		}

		/// <summary>
		/// Returns the fluent interface wrapper for a service object.
		/// </summary>
		/// <typeparam name="T">Type of the service.</typeparam>
		/// <param name="serviceInstance">Service instance to get the wrapper for.</param>
		/// <returns>Wrapper instance.</returns>
		public static ServiceInstanceWrapper<T> From<T>(T serviceInstance)
		{
			return new ServiceInstanceWrapper<T>(serviceInstance);
		}

		/// <summary>
		/// Returns an <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>
		/// instance describing the given service.
		/// </summary>
		/// <typeparam name="T">Registered type of the service to get the meta information about.</typeparam>
		/// <returns>The <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see> instance
		/// or <c>null</c>, if the service is not defined.</returns>
		public static INQServiceInfo ServiceMetaInfo<T>()
		{
			return NQServiceManager.Instance.GetServiceInfo(typeof(T));
		}

		/// <summary>
		/// Returns an <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>
		/// instance describing the given service.
		/// </summary>
		/// <param name="serviceInterface">Registered type of the service to get the meta information about.</param>
		/// <returns>The <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see> instance
		/// or <c>null</c>, if the service is not defined.</returns>
		public static INQServiceInfo ServiceMetaInfo(Type serviceInterface)
		{
			return NQServiceManager.Instance.GetServiceInfo(serviceInterface);
		}

		/// <summary>
		/// Returns information about a certain service from a service object.
		/// </summary>
		/// <param name="serviceObject">Instance of a service.</param>
		/// <returns>Instance of <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>.</returns>
		public static INQServiceInfo ObjectMetaInfo(object serviceObject)
		{
			return NQServiceManager.Instance.GetServiceInfoFromObject(serviceObject);
		}

		/// <summary>
		/// Returns an <see cref="AWZhome.NQ.Core.INQComponentInfo">INQComponentInfo</see>
		/// instance describing the given component.
		/// </summary>
		/// <returns>The <see cref="AWZhome.NQ.Core.INQComponentInfo">INQComponentInfo</see> instance
		/// or <c>null</c>, if the component is not defined.</returns>
		public static INQComponentInfo ComponentMetaInfo(string componentName)
		{
			return NQServiceManager.Instance.GetComponentInfo(componentName);
		}

		/// <summary>
		/// Returns an array of names of currently loaded components.
		/// </summary>
		/// <returns>Array of component names.</returns>
		public static string[] AllComponents
		{
			get
			{
				return NQServiceManager.Instance.GetComponentList();
			}
		}

		/// <summary>
		/// Returns an array of all currently registered service interfaces.
		/// </summary>
		/// <returns>Array of service names.</returns>
		public static System.Type[] AllServices
		{
			get
			{
				return NQServiceManager.Instance.GetServiceList();
			}
		}

		/// <summary>
		/// Returns an array of names of all currently created AttachLists.
		/// </summary>
		/// <returns>Array of AttachList names.</returns>
		public static string[] AllAttachLists
		{
			get
			{
				return NQServiceManager.Instance.GetAllAttachLists();
			}
		}

		/// <summary>
		/// Checks if a certain single-instance service is running.
		/// </summary>
		/// <typeparam name="T">Registered interface type of the service.</typeparam>
		/// <returns><c>true</c>, if the service is existing, <c>false</c> otherwise.</returns>
		public static bool IsRunning<T>()
		{
			return NQServiceManager.Instance.IsServiceRunning(typeof(T));
		}

		/// <summary>
		/// Checks if a certain multi-instance service is registered and an instance can be created.
		/// </summary>
		/// <typeparam name="T">Registered interface type of the service.</typeparam>
		/// <returns><c>true</c>, if an instance of the service can be created, <c>false</c> otherwise.</returns>
		public static bool IsCreatable<T>()
		{
			return NQServiceManager.Instance.IsServiceCreatable(typeof(T));
		}

		/// <summary>
		/// Checks if a certain component is loaded.
		/// </summary>
		/// <param name="componentName">Name of component.</param>
		/// <returns><c>true</c>, if the component is loaded, <c>false</c> otherwise.</returns>
		public static bool IsComponent(string componentName)
		{
			return NQServiceManager.Instance.IsComponentLoaded(componentName);
		}

		/// <summary>
		/// Exists the application firing the 
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.AppExitRequested">AppExitRequested</see>.
		/// </summary>
		/// <remarks>
		/// The Exit method exits the process directly. GUI applications should perform
		/// a regular exit from the window message loop instead. By setting the 
		/// <see cref="AWZhome.NQ.Core.NQCancelEventArgs.Cancel">Cancel</see> property
		/// to <c>true</c> in AppExitRequested the exit can be aborted to end the message loop
		/// properly.
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.ExitApplication"/>
		public static void Exit()
		{
			NQServiceManager.Instance.ExitApplication();
		}

		/// <summary>
		/// Returns the directory where all component assemblies are loaded from.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.ComponentPath"/>
		public static string ComponentPath
		{
			get
			{
				return NQServiceManager.Instance.ComponentPath;
			}
		}

		/// <summary>
		/// Returns the mode of the running NQ application.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.HostMode"/>
		public static NQHostMode HostMode
		{
			get
			{
				return NQServiceManager.Instance.HostMode;
			}
		}

		/// <summary>
		/// Returns the synchronization object of the service manager which can be used to
		/// synchronize threads.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.SyncObject"/>
		public static object SyncObject
		{
			get
			{
				return NQServiceManager.Instance.SyncObject;
			}
		}

		/// <summary>
		/// Does a thread and type safe call to the given delegate of a method without return value
		/// using the GUI thread's context in GUI mode.
		/// </summary>
		/// <typeparam name="P">Type of the delegate's parameter.</typeparam>
		/// <param name="method">The delegate object to be used for the call.</param>
		/// <param name="param">The method parameter.</param>
		/// <remarks>
		/// When in GUI mode (see also <see cref="AWZhome.NQ.Core.INQServiceManager.HostMode">HostMode</see>)
		/// the method marshals the call into the GUI thread's context. This is very useful for graphical
		/// Windows applications that have to access GUI elements from additional threads. If not in GUI mode
		/// the method creates a critical section around the call using the internal synchronization object (see
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.SyncObject">SyncObject</see>).
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.InvokeSyncMethod#P"/>
		public static void InvokeSync<P>(NQSynchronizedProcDelegate<P> method, P param)
		{
			NQServiceManager.Instance.InvokeSyncMethod<P>(method, param);
		}

		/// <summary>
		/// Does a thread and type safe call to the given delegate using the GUI thread's
		/// context in GUI mode.
		/// </summary>
		/// <typeparam name="P">Type of the delegate's parameter.</typeparam>
		/// <typeparam name="R">Type of the delegate's return value.</typeparam>
		/// <param name="method">The delegate object to be used for the call.</param>
		/// <param name="param">The method parameter.</param>
		/// <returns>The return value of the called delegate.</returns>
		/// <remarks>
		/// When in GUI mode (see also <see cref="AWZhome.NQ.Core.INQServiceManager.HostMode">HostMode</see>)
		/// the method marshals the call into the GUI thread's context. This is very useful for graphical
		/// Windows applications that have to access GUI elements from additional threads. If not in GUI mode
		/// the method creates a critical section around the call using the internal synchronization object (see
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.SyncObject">SyncObject</see>).
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.Core.INQServiceManager.InvokeSyncMethod#P,R"/>
		public static R InvokeSync<P, R>(NQSynchronizedDelegate<P, R> method, P param)
		{
			return NQServiceManager.Instance.InvokeSyncMethod<P, R>(method, param);
		}
	}
}
